home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / scope / 076-100 / scopedisk81 / wkeys / wkeys-handler.c < prev    next >
C/C++ Source or Header  |  1995-03-19  |  13KB  |  470 lines

  1. /*
  2.  *  wKeys-Handler.c   Input Handler for wKeyw, which moves and activates 
  3.  *                    windows and screensin response to keystrokes
  4.  *
  5.  *              Copyright (c) 1987,1988 by Davide P. Cervone
  6.  *  You may use this code provided this copyright notice is left intact.
  7.  */
  8.  
  9. #include <exec/types.h>
  10. #include <exec/memory.h>
  11. #include <devices/inputevent.h>
  12. #include <intuition/intuitionbase.h>
  13.  
  14. #include "wKeys.h"
  15.  
  16. static char *program = "wKeys-Handler";
  17. static int   version = 3;
  18. static char *date    = "January 1988";
  19. static char *author  = "Copyright (c) 1987,1988 by Davide P. Cervone";
  20.  
  21. extern struct Layer *WhichLayer();
  22. extern struct IntuiMessage *GetMsg();
  23. extern struct IntuiMessage *AllocMem();
  24. extern void myHandlerStub();
  25.  
  26. #define WINDOW(layer)   ((struct Window *)((layer)->Window))
  27.  
  28. #define SCREENTOP\
  29.    (theScreen->TopEdge << ((theScreen->ViewPort.Modes & LACE)? 0: 1))
  30.  
  31. #define IMSIZE          ((ULONG)sizeof(struct IntuiMessage))
  32. #define NEWMESSAGE(m)   (m = AllocMem(IMSIZE,MEMF_PUBLIC | MEMF_CLEAR))
  33. #define FREEMESSAGE(m)  FreeMem(m,IMSIZE);
  34.  
  35. struct IntuitionBase *IntuitionBase = NULL;
  36. struct LayersBase    *LayersBase    = NULL;
  37. struct SysBase       *SysBase       = NULL;
  38.  
  39. static struct HotKey *Key = NULL;
  40. static int KeyCount = 0;
  41. static struct MsgPort *ReplyPort = NULL;
  42.  
  43. /*
  44.  *  Setup()
  45.  *
  46.  *  wKeys calls LoadSeg() to get this handler into memory.  The segment
  47.  *  that it gets points to this routine.  wKeys calls Setup() and 
  48.  *  passes the IntuitionBase, LayersBase and SysBase pointers that it
  49.  *  has initialized (with OpenLibrary()).  wKeys also passes the KeyArray
  50.  *  and KeyCount which hold the key bindings.  Setup returns a pointer to
  51.  *  the actual input handler, which wKeys installs, and sets the version
  52.  *  number so that hotKey can report the handler's version.
  53.  */
  54.  
  55. long Setup(Ibase,Lbase,Sbase,theKeys,Count,Port,VersionPtr)
  56. struct IntuitionBase *Ibase;
  57. struct LayersBase *Lbase;
  58. struct SysBase *Sbase;
  59. struct HotKey *theKeys;
  60. struct MsgPort *Port;
  61. int *VersionPtr;
  62. int Count;
  63. {
  64.    IntuitionBase = Ibase;
  65.    LayersBase = Lbase;
  66.    SysBase = Sbase;
  67.    Key = theKeys;
  68.    KeyCount = Count;
  69.    ReplyPort = Port;
  70.    *VersionPtr = version;
  71.    return((long) &myHandlerStub);
  72. }
  73.  
  74. /*
  75.  *  TopWindow()
  76.  *
  77.  *  Find the top window of the specified screen.  Start at the top layer of
  78.  *  the screen and move backward as long as the layer exists and has no
  79.  *  window connected to it.  Return the window associated with the final 
  80.  *  layer, if any.
  81.  */
  82.  
  83. static struct Window *TopWindow(theScreen)
  84. struct Screen *theScreen;
  85. {
  86.    struct Window *theWindow = NULL;
  87.    struct Layer *theLayer;
  88.    
  89.    theLayer = theScreen->LayerInfo.top_layer;
  90.    while (theLayer && WINDOW(theLayer) == NULL) theLayer = theLayer->back;
  91.    if (theLayer) theWindow = WINDOW(theLayer);
  92.    return(theWindow);
  93. }
  94.  
  95. /*
  96.  *  BottomWindow()
  97.  *
  98.  *  Find the bottom window of the specified screen.  Start at the top layer
  99.  *  and as long as the layer exists, go to the next layer back.  If the
  100.  *  layer has a window attached, consider that to be the bottom window until
  101.  *  a lower one is found.
  102.  */
  103.  
  104. static struct Window *BottomWindow(theScreen)
  105. struct Screen *theScreen;
  106. {
  107.    struct Window *theWindow = NULL;
  108.    struct Layer *theLayer = theScreen->LayerInfo.top_layer;
  109.    
  110.    while (theLayer)
  111.    {
  112.       if (WINDOW(theLayer) && isIconified(WINDOW(theLayer)) == FALSE)
  113.          theWindow = WINDOW(theLayer);
  114.       theLayer = theLayer->back;
  115.    }
  116.    return(theWindow);
  117. }
  118.  
  119. /*
  120.  *  NextWindow()
  121.  *
  122.  *  Find the next window below the specified window (wrap arround to the top
  123.  *  if the window is the bottom one).  Start with the window's layer and go
  124.  *  back until a layer with a window is found, or no more layers exist.  If
  125.  *  a window was found, return it, otherwise, use the top window.
  126.  */
  127.  
  128. static struct Window *NextWindow(theWindow)
  129. struct Window *theWindow;
  130. {
  131.    struct Layer  *theLayer  = theWindow->WLayer;
  132.    
  133.    do
  134.       theLayer = theLayer->back;
  135.    while (theLayer && (WINDOW(theLayer) == NULL ||
  136.           isIconified(WINDOW(theLayer))));
  137.    if (theLayer)
  138.       theWindow = WINDOW(theLayer);
  139.      else
  140.       theWindow = TopWindow(theWindow->WScreen);
  141.    return(theWindow);
  142. }
  143.  
  144. /*
  145.  *  PreviousWindow()
  146.  *
  147.  *  Find the window that is on top of the specified window (or NULL if there
  148.  *  are no windows above it).  Start with the window's layer, and move to
  149.  *  the layer in front until a layer with a (different) window is found, or
  150.  *  until no more layers exist.  If a window was found, return it, otherwise
  151.  *  return NULL.
  152.  */
  153.  
  154. static struct Window *PreviousWindow(theWindow)
  155. struct Window *theWindow;
  156. {
  157.    struct Layer  *theLayer  = theWindow->WLayer;
  158.    
  159.    do
  160.       theLayer = theLayer->front;
  161.    while (theLayer && (WINDOW(theLayer) == NULL ||
  162.                        WINDOW(theLayer) == theWindow));
  163.    if (theLayer)
  164.       theWindow = WINDOW(theLayer);
  165.      else
  166.       theWindow = NULL;
  167.    return(theWindow);
  168. }
  169.  
  170. /*
  171.  *  BackScreenToFront()
  172.  *
  173.  *  Bring the bottom-most screen to the top, and activate its top window.
  174.  *  While there is a screen following the current one, move the the next screen.
  175.  *  Bring that screen to the front and find its top window.  If one was found,
  176.  *  activate the window.
  177.  */
  178.  
  179. static void BackScreenToFront()
  180. {
  181.    struct Screen *theScreen = IntuitionBase->FirstScreen;
  182.    struct Window *theWindow;
  183.    
  184.    if (theScreen)
  185.    {
  186.       while (theScreen->NextScreen) theScreen = theScreen->NextScreen;
  187.       ScreenToFront(theScreen);
  188.       theWindow = TopWindow(theScreen);
  189.       if (theWindow) ActivateWindow(theWindow);
  190.    }
  191. }
  192.  
  193. /*
  194.  *  FrontScreenToBack()
  195.  *
  196.  *  Move the top screen to the back and activate the top window on the new
  197.  *  top screen.
  198.  */
  199.  
  200. static void FrontScreenToBack()
  201. {
  202.    struct Screen *theScreen = IntuitionBase->FirstScreen;
  203.    struct Window *theWindow;
  204.  
  205.    if (theScreen)
  206.    {
  207.       ScreenToBack(theScreen);
  208.       theScreen = IntuitionBase->FirstScreen;
  209.       if (theScreen)
  210.       {
  211.          theWindow = TopWindow(theScreen);
  212.          if (theWindow) ActivateWindow(theWindow);
  213.       }
  214.    }
  215. }
  216.  
  217. /*
  218.  *  ActivatePreviousWindow()
  219.  *
  220.  *  Get the window previous to the current window (if none, then get the
  221.  *  bottom window in the active screen), and activate that window.
  222.  */
  223.  
  224. static void ActivatePreviousWindow()
  225. {
  226.    struct Window *theWindow = PreviousWindow(IntuitionBase->ActiveWindow);
  227.    
  228.    if (theWindow == NULL) theWindow = BottomWindow(IntuitionBase->ActiveScreen);
  229.    if (theWindow) ActivateWindow(theWindow);
  230. }
  231.  
  232. /*
  233.  *  ActivateNextWindow()
  234.  *
  235.  *  Get the window below the current window and activate it.
  236.  */
  237.  
  238. static void ActivateNextWindow()
  239. {
  240.    struct Window *theWindow = NextWindow(IntuitionBase->ActiveWindow);
  241.    
  242.    if (theWindow) ActivateWindow(theWindow);
  243. }
  244.  
  245. /*
  246.  *  CurrentWindowToBack()
  247.  *
  248.  *  Send the current window to the back of the list.
  249.  */
  250.  
  251. static void CurrentWindowToBack()
  252. {
  253.    struct Window *theWindow = IntuitionBase->ActiveWindow;
  254.    
  255.    if (theWindow && (theWindow->Flags & BACKDROP) == 0)
  256.       WindowToBack(theWindow);
  257. }
  258.  
  259. /*
  260.  *  CurrentWindowToFront()
  261.  *
  262.  *  Send the current window to the top of the list.
  263.  */
  264.  
  265. static void CurrentWindowToFront()
  266. {
  267.    struct Window *theWindow = IntuitionBase->ActiveWindow;
  268.    
  269.    if (theWindow) WindowToFront(theWindow);
  270. }
  271.  
  272. /*
  273.  *  BackWindowToFront()
  274.  *
  275.  *  Move the bottom window to the top and activate it.  Get the bottom window,
  276.  *  skipping over backdrop windows.  If one is found, bring it to the front,
  277.  *  and activate it.
  278.  */
  279.  
  280. static void BackWindowToFront()
  281. {
  282.    struct Window *theWindow = BottomWindow(IntuitionBase->ActiveScreen);
  283.    
  284.    if (theWindow)
  285.    {
  286.       while (theWindow && (theWindow->Flags & BACKDROP))
  287.          theWindow = PreviousWindow(theWindow);
  288.       if (theWindow)
  289.       {
  290.          WindowToFront(theWindow);
  291.          ActivateWindow(theWindow);
  292.       }
  293.    }
  294. }
  295.  
  296. /*
  297.  *  FrontWindowToBack()
  298.  *
  299.  *  Move the top window to the back, and activate the new top window.
  300.  *  Get the top window, and then the window following it.  Send the top window
  301.  *  to the back, and activate the next window.
  302.  */
  303.  
  304. static void FrontWindowToBack()
  305. {
  306.    struct Window *theWindow  = TopWindow(IntuitionBase->ActiveScreen);
  307.    struct Window *nextWindow = NextWindow(theWindow);
  308.    
  309.    if (theWindow && (theWindow->Flags & BACKDROP) == 0)
  310.    {
  311.       WindowToBack(theWindow);
  312.       if (nextWindow) ActivateWindow(nextWindow);
  313.    }
  314. }
  315.  
  316. /*
  317.  *  CloseCurrentWindow()
  318.  *
  319.  *  If the current window has the CLOSEWINDOW IDCMP flag, then 
  320.  *  send it a CLOSEWINDOW IDCMP message.  Unfortunately, the workbench
  321.  *  has the CLOSWINDOW flag set, and it crashes if you send it a close
  322.  *  message; therefore, CloseCurrentWindow will not sent a CLOSWINDOW
  323.  *  event to a BACKDROP window.  This seemed the easiest way to rule out
  324.  *  the workbench without too much overhead.
  325.  *
  326.  *  The message will be replied to the ReplyPort, which is checked in the 
  327.  *  input handler.  Any messages that get returned are freed.
  328.  */
  329.  
  330. static void CloseCurrentWindow()
  331. {
  332.    struct Window *theWindow = IntuitionBase->ActiveWindow;
  333.    struct IntuiMessage *theMessage;
  334.    
  335.    if (theWindow && (theWindow->IDCMPFlags & CLOSEWINDOW) && 
  336.       (theWindow->Flags & BACKDROP) == 0)
  337.    {
  338.       if (NEWMESSAGE(theMessage))
  339.       {
  340.          theMessage->Class = CLOSEWINDOW;
  341.          theMessage->IDCMPWindow = theWindow;
  342.          theMessage->ExecMessage.mn_ReplyPort = ReplyPort;
  343.          PutMsg(theWindow->UserPort,theMessage);
  344.       }
  345.    }
  346. }
  347.  
  348. /*
  349.  *  WindowToIcon()
  350.  *
  351.  *  Iconify the current window if wIconify is running.
  352.  */
  353.  
  354. static void WindowToIcon()
  355. {
  356.    struct Window *theWindow = IntuitionBase->ActiveWindow;
  357.    
  358.    if (theWindow) wIconifyWindow(theWindow);
  359. }
  360.  
  361. /*
  362.  *  IconToWindow()
  363.  *
  364.  *  Restore the selected wIconify icon to a window.  The workbench must
  365.  *  be the active window, and wIconify must be running, and a window icon
  366.  *  must be selected.
  367.  */
  368.  
  369. static void IconToWindow()
  370. {
  371.    wRestoreWindow(NULL);
  372. }
  373.  
  374. /*
  375.  *  SelectNextIcon()
  376.  *
  377.  *  Tells wIconify to select the next window icon on the workbench.  If no
  378.  *  icon is selected, then select the first icon.
  379.  */
  380.  
  381. static void SelectNextIcon()
  382. {
  383.    wNextIcon();
  384. }
  385.  
  386. /*
  387.  *  Array of functions that perform the different actions associated with 
  388.  *  the hot-keys.  These are called by the handler routine.
  389.  */
  390.  
  391. typedef void (*FUNCTION)();
  392.  
  393. static FUNCTION Action[] =
  394. {
  395.    NULL,
  396.    &BackScreenToFront,
  397.    &FrontScreenToBack,
  398.    &ActivatePreviousWindow,
  399.    &ActivateNextWindow,
  400.    &CurrentWindowToBack,
  401.    &CurrentWindowToFront,
  402.    &BackWindowToFront,
  403.    &FrontWindowToBack,
  404.    &CloseCurrentWindow,
  405.    &WindowToIcon,
  406.    &IconToWindow,
  407.    &SelectNextIcon
  408. };
  409.  
  410. /*
  411.  *  myHandler()
  412.  *
  413.  *  This is the input handler.  
  414.  *  First check if there are any returned CLOSEWINDOW events, then,
  415.  *  For each event in the event list:
  416.  *  If the event is a raw key event, then
  417.  *    make the KeyCode longword for that event's code and qualifier,
  418.  *    binary search the Key[] array for a matching entry (only consider
  419.  *      the qualifiers specified by the KeyMask).  Since most keys pressed
  420.  *      will NOT match a hot-key, we want the search to be as fast as 
  421.  *      possible, so we use a binary search rather than a linear search.
  422.  *    set NoHotKey if the key is not a hot key.
  423.  *  if the key was not a hot key,
  424.  *    go on to the next key
  425.  *   otherwise,
  426.  *    perform the function for the specified hot key,
  427.  *    remove the hot key from the event list.
  428.  *
  429.  *  When all the events have been checked, return the event list so that
  430.  *  Intuition can do its thing.
  431.  */
  432.  
  433. struct InputEvent *myHandler(EventList,data)
  434. struct InputEvent *EventList;
  435. APTR data;
  436. {
  437.    register struct InputEvent **EventPtr = &EventList;
  438.    register struct InputEvent *theEvent;
  439.    register long   theKey;
  440.    register short  Num,Min,Max;
  441.    register long   NoHotKey;
  442.    struct IntuiMessage *theMessage;
  443.  
  444.    while (theMessage = GetMsg(ReplyPort)) FREEMESSAGE(theMessage);
  445.  
  446.    Forbid();
  447.    while((theEvent = *EventPtr) != NULL)
  448.    {
  449.       NoHotKey = TRUE;
  450.       if (theEvent->ie_Class == IECLASS_RAWKEY)
  451.       {
  452.          theKey = KEY(theEvent);
  453.          Max = KeyCount; Min = -1;
  454.          while ((Num = (Min + Max) >> 1) != Min &&
  455.                 (NoHotKey = (theKey & Key[Num].hk_KeyMask) -
  456.                              Key[Num].hk_KeyCode) != 0)
  457.             if (NoHotKey > 0) Min = Num; else Max = Num;
  458.       }
  459.       if (NoHotKey)
  460.       {
  461.          EventPtr = &(theEvent->ie_NextEvent);
  462.       } else {
  463.          (*(Action[Key[Num].hk_Action]))();
  464.          *EventPtr = theEvent->ie_NextEvent;
  465.       }
  466.    }
  467.    Permit();
  468.    return(EventList);
  469. }
  470.